package com.mysen.sso;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.fastjson.JSON;
import com.mysen.exception.MaikeServiceException;
import com.mysen.model.Response;
import com.mysen.sso.cache.SessionCache;

public class PermissionCheck extends HandlerInterceptorAdapter {

	private static final Logger LOGGER = LoggerFactory.getLogger(PermissionCheck.class);
	
	private SessionCache sessionCache;
	
	public void setSessionCache(SessionCache sessionCache) {
		this.sessionCache = sessionCache;
	}
	
	private String[] pass;
	
	public void setPass(String[] pass) {
		this.pass = pass;
	}
	public String[] getPass() {
		return pass;
	}
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		boolean permission = false;
		String method = request.getMethod().toUpperCase();
		String uri = request.getRequestURI();
		String passCheck = method + ":" + uri;
		for(String path : pass) {
			if(passCheck.matches(path)) {
				permission = true;
				break;
			}
		}
		if (!permission && handler instanceof HandlerMethod) {
			HandlerMethod hm = (HandlerMethod) handler;
			String uridef = getUriDef(hm, method);
			permission = sessionCache.getPermission(request, uridef) != null;
			
			LOGGER.info("check permission:{}, result:{}", uridef, permission);
			if(!permission) {
				response.setStatus(401);
				Response<?> resp = new Response<>();
				resp.setSuccess(false);
				resp.setErrorMsg(Response.MSG_UNAUTHORIZED);
				response.setContentType("application/json; charset=UTF-8");
				response.getWriter().write(JSON.toJSONString(resp));
			}
		}
		return permission;
	}

	private String getUriDef(HandlerMethod hm, String reqm) {
		Class<?> clazz = hm.getBean().getClass();
		RequestMapping mapping = clazz.getAnnotation(RequestMapping.class);
		String[] baseMappings = new String[] {};
		String[] methodMappings = new String[] {};
		if(mapping != null) {
			baseMappings = mapping.value();
		}
		RequestMapping method = hm.getMethod().getAnnotation(RequestMapping.class);
		if(method != null) {
			methodMappings = method.value();
		}else if("GET".equalsIgnoreCase(reqm)) {
			methodMappings = hm.getMethod().getAnnotation(GetMapping.class).value();
		}else if("POST".equalsIgnoreCase(reqm)) {
			methodMappings = hm.getMethod().getAnnotation(PostMapping.class).value();
		}else if("DELETE".equalsIgnoreCase(reqm)) {
			methodMappings = hm.getMethod().getAnnotation(DeleteMapping.class).value();
		}else if("PATCH".equalsIgnoreCase(reqm)) {
			methodMappings = hm.getMethod().getAnnotation(PatchMapping.class).value();
		}else if("PUT".equalsIgnoreCase(reqm)) {
			methodMappings = hm.getMethod().getAnnotation(PutMapping.class).value();
		}else {
			throw new MaikeServiceException("not support method!");
		}
		String base = "", md="";
		if(baseMappings != null && baseMappings.length > 0) {
			baseMappings[0] = baseMappings[0].startsWith("/") ? baseMappings[0] : "/"+baseMappings[0];
			baseMappings[0] = baseMappings[0].endsWith("/") ? baseMappings[0].substring(0, baseMappings[0].length() - 1) : baseMappings[0];
			base = baseMappings[0];
		}
		
		if(methodMappings != null && methodMappings.length > 0) {
			methodMappings[0] = methodMappings[0].startsWith("/") ? methodMappings[0] : "/"+methodMappings[0];
			methodMappings[0] = methodMappings[0].endsWith("/") ? methodMappings[0].substring(0, methodMappings[0].length() - 1) : methodMappings[0];
			md = methodMappings[0];
		}
		
		return base + md;
	}

}
